package tcp_servicer

import (
	"log"
	"net"
	"os"
	"regexp"
	"strconv"
	"time"
)

//type Message chan string
var logger *log.Logger
var maxDevices int = 72 //default 72
var tokenSeq int = 0

type Token chan int
type DeviceTable map[string]*Device
type Tcp_Server struct {
	listener net.Listener
	devices  DeviceTable
	tokens   Token
	pending  chan net.Conn
	quiting  chan string
	incoming chan string
	outgoing chan string
	// quitAnnouncement chan bool // close this chan when server exit
}

func init() {

	maxDevs := os.Getenv("MAXDEVS")

	if len(maxDevs) > 0 {
		max, err := strconv.Atoi(maxDevs)
		if err == nil && max > 25 { //minum value 12
			maxDevices = max // default value , always have a value be set to the variable maxDevices
		}
	}

	logger = log.New(os.Stdout, "TCP SVR>", log.LstdFlags|log.Lshortfile)

}

func (self *Tcp_Server) listen() {

	go func() {
		for {
			select {
			// case msg := <-self.incoming:
			// 	self.process(msg)
			case conn := <-self.pending:
				self.join(conn)
			case device_id := <-self.quiting:
				logger.Printf("*Tcp_Server.listen: device[%v] <- self.quiting.... \n", device_id)
				self.leave(device_id)

			}

		}

	}()
}

func (self *Tcp_Server) join(conn net.Conn) {

	device, msg := CreateDevice(conn, self)
	if device == nil {
		logger.Printf("No device created.\n")
		return
	}
	device_id := device.GetDevice_ID()

	self.devices[device_id] = device
	logger.Printf("Device [%v] connected to server.", device_id)

	go func() {

		for {

			message, ok := <-device.incoming
			if ok {
				msg := regexp.MustCompile(";").Split(message, -1)

				logger.Printf("[%v]>>[%v]:%v;%v;\n", device_id, msg[1], msg[2], msg[3])
				switch msg[0] {
				case "#":

					device.db <- DevMsg{msg[2], msg[3]}

				case "@":
					bridge := self.devices[msg[1]]
					if bridge != nil {

						bridge.db <- DevMsg{msg[2], msg[3]}

					} else {
						logger.Printf("Device [%v] is not active.\n", msg[1])
					}
				}

			}
			conn.SetReadDeadline(time.Now().Add(60 * 3.1 * time.Second))

		}
		logger.Printf("Device[%v] Time out ....\n", device_id)
		device.quit()
	}()

	go func() {
		for {
			device_id := <-device.quiting
			logger.Printf("Device [%v] is quiting \n", device_id)
			self.quiting <- device_id

		}

	}()

	device.incoming <- msg
}

func (self *Tcp_Server) leave(device_id string) {
	logger.Printf("*Tcp_Server.leave...... parameter: device_id=[%v]\n", device_id)
	if device_id != "" {
		d, ok := self.devices[device_id]
		if ok {
			d.close()
			delete(self.devices, device_id)
			self.generateToken()
			logger.Printf(" Device [%v] closed.\n", device_id)

		}
	}
	logger.Printf(" Device [%v] left.\n", device_id)

}

func CreateTcpServer() *Tcp_Server {
	server := &Tcp_Server{
		devices: make(DeviceTable, maxDevices),
		tokens:  make(Token, maxDevices),
		pending: make(chan net.Conn),

		quiting:  make(chan string),
		incoming: make(chan string),
		outgoing: make(chan string),

		// quitAnnouncement: make(chan bool),
	}

	server.listen()
	return server
}

func (self *Tcp_Server) Start(connString string) {

	tcpAddr, err := net.ResolveTCPAddr("tcp4", connString)
	checkError(err)

	self.listener, _ = net.ListenTCP("tcp", tcpAddr)
	logger.Printf("Tcp Server %p starts at %s \n", self, tcpAddr)

	for i := 0; i < maxDevices; i++ {
		self.generateToken()
	}
	logger.Printf("Generated Token #:%v\n", tokenSeq)

	for {

		conn, err := self.listener.Accept()
		if err != nil {
			logger.Printf("Error at Tcp_Server.Start Accept():%v\n", err)

			continue
		}

		logger.Printf("A new device [%v] kicks \n", conn)

		self.takeToken()
		self.pending <- conn

	}

}

func (self *Tcp_Server) generateToken() {
	self.tokens <- tokenSeq
	tokenSeq++
	// logger.Printf("Generated Token #:%v\n", tokenSeq)
}

func (self *Tcp_Server) takeToken() {
	t := <-self.tokens
	logger.Printf("Taken Token #:%v\n", t)
}

func checkError(err error) {
	if err != nil {
		logger.Printf("Fatal error: %s\n", err.Error())
		os.Exit(1)
	}
}
